home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / graphics / flick_12.zip / FLICK.C < prev    next >
C/C++ Source or Header  |  1994-02-18  |  43KB  |  1,387 lines

  1. /*****************************************************************************
  2.  
  3.         Flick FLI-format Animation Viewer v1.2          19 Feb 1994
  4.         --------------------------------------
  5.  
  6.  
  7. This program plays FLI/FLC-format bitmapped animation files on any ECS
  8. or AGA Amiga running OS2.04 or higher.  FLI/FLC-format files are
  9. produced by Autodesk Animator and Autodesk 3D Studio on a PC, as well
  10. as by other programs.
  11.  
  12. The files in this archive may be distributed anywhere provided they are
  13. unmodified and are not sold for profit.
  14.  
  15. Ownership and copyright of all files remains with the author:
  16.  
  17.     Peter McGavin, 86 Totara Crescent, Lower Hutt, New Zealand.
  18.     e-mail: peterm@maths.grace.cri.nz
  19.  
  20. *****************************************************************************/
  21.  
  22. #include "includes.h"
  23.  
  24. const char version[] = "$VER: Flick 1.2 " __AMIGADATE__ ;
  25.  
  26. long __oslibversion = 37;    /* we require at least OS2.0 */
  27.  
  28. char __stdiowin[] = "CON:20/50/500/130/Flick";
  29. char __stdiov37[] = "/AUTO/CLOSE";
  30.  
  31. void __asm c2p_8 (register __a0 UBYTE *chunky_data,
  32.                   register __a1 PLANEPTR raster,
  33.                   register __a3 UBYTE *buff0,
  34.                   register __a4 UBYTE *buff1,
  35.                   register __a5 struct Library *TimerBase,
  36.                   register __a6 struct GfxBase *GfxBase,
  37.                   register __d0 struct Library *UtilityBase,
  38.                   register __d1 ULONG plsiz);
  39.  
  40. void __asm c2p_6 (register __a0 UBYTE *chunky_data,
  41.                   register __a1 PLANEPTR raster,
  42.                   register __a3 UBYTE *buff0,
  43.                   register __a4 UBYTE *buff1,
  44.                   register __a5 struct Library *TimerBase,
  45.                   register __a6 struct GfxBase *GfxBase,
  46.                   register __d0 struct Library *UtilityBase,
  47.                   register __d1 ULONG plsiz);
  48.  
  49. void __asm c2p_4 (register __a0 UBYTE *chunky_data,
  50.                   register __a1 PLANEPTR raster,
  51.                   register __a3 UBYTE *buff0,
  52.                   register __a4 UBYTE *buff1,
  53.                   register __a5 struct Library *TimerBase,
  54.                   register __a6 struct GfxBase *GfxBase,
  55.                   register __d0 struct Library *UtilityBase,
  56.                   register __d1 ULONG plsiz);
  57.  
  58. void __asm c2p320x200x8 (register __a0 UBYTE *chunky_data,
  59.                          register __a1 PLANEPTR raster,
  60.                          register __a3 UBYTE *buff0,
  61.                          register __a4 UBYTE *buff1,
  62.                          register __a5 struct Library *TimerBase,
  63.                          register __a6 struct GfxBase *GfxBase,
  64.                          register __d0 struct Library *UtilityBase);
  65.  
  66. void __asm c2p320x200x6 (register __a0 UBYTE *chunky_data,
  67.                          register __a1 PLANEPTR raster,
  68.                          register __a3 UBYTE *buff0,
  69.                          register __a4 UBYTE *buff1,
  70.                          register __a5 struct Library *TimerBase,
  71.                          register __a6 struct GfxBase *GfxBase,
  72.                          register __d0 struct Library *UtilityBase);
  73.  
  74. void __asm c2p_8_040 (register __a0 UBYTE *chunky_data,
  75.                       register __a1 PLANEPTR raster,
  76.                       register __d1 ULONG plsiz);
  77.  
  78. void __asm c2p_6_040 (register __a0 UBYTE *chunky_data,
  79.                       register __a1 PLANEPTR raster,
  80.                       register __d1 ULONG plsiz);
  81.  
  82. void __asm c2p_4_040 (register __a0 UBYTE *chunky_data,
  83.                       register __a1 PLANEPTR raster,
  84.                       register __d1 ULONG plsiz);
  85.  
  86. void __asm c2p320x200x8_040 (register __a0 UBYTE *chunky_data,
  87.                              register __a1 PLANEPTR raster);
  88.  
  89. void __asm c2p320x200x6_040 (register __a0 UBYTE *chunky_data,
  90.                              register __a1 PLANEPTR raster);
  91.  
  92. void __asm c2p_8_cmp (register __a0 UBYTE *chunky_data,
  93.                       register __a1 PLANEPTR raster,
  94.                       register __a2 UBYTE *compare_data,
  95.                       register __d1 ULONG plsiz);
  96.  
  97. void __asm c2p_6_cmp (register __a0 UBYTE *chunky_data,
  98.                       register __a1 PLANEPTR raster,
  99.                       register __a2 UBYTE *compare_data,
  100.                       register __d1 ULONG plsiz);
  101.  
  102. void __asm c2p_4_cmp (register __a0 UBYTE *chunky_data,
  103.                       register __a1 PLANEPTR raster,
  104.                       register __a2 UBYTE *compare_data,
  105.                       register __d1 ULONG plsiz);
  106.  
  107. void __asm c2p320x200x8_cmp (register __a0 UBYTE *chunky_data,
  108.                              register __a1 PLANEPTR raster,
  109.                              register __a2 UBYTE *compare_data);
  110.  
  111. void __asm c2p320x200x6_cmp (register __a0 UBYTE *chunky_data,
  112.                              register __a1 PLANEPTR raster,
  113.                              register __a2 UBYTE *compare_data);
  114.  
  115. #define FLI_256_COLOR  4
  116. #define FLI_SS2        7
  117. #define FLI_COLOR     11
  118. #define FLI_LC        12
  119. #define FLI_BLACK     13
  120. #define FLI_BRUN      15
  121. #define FLI_COPY      16
  122. #define FLI_PSTAMP    18
  123.  
  124. struct header {
  125.   ULONG size;
  126.   UWORD magic;
  127.   UWORD frames;
  128.   UWORD width;
  129.   UWORD height;
  130.   UWORD depth;
  131.   UWORD flags;
  132.   ULONG speed;
  133.   UWORD reserved1;
  134.   ULONG created;
  135.   ULONG creator;
  136.   ULONG updated;
  137.   ULONG updater;
  138.   UWORD aspectx;
  139.   UWORD aspecty;
  140.   UBYTE reserved2[38];
  141.   ULONG oframe1;
  142.   ULONG oframe2;
  143.   UBYTE reserved3[40];
  144. };
  145.  
  146. struct frameheader {
  147.   ULONG size;
  148.   UWORD magic;
  149.   UWORD chunks;
  150.   UBYTE expand[8];
  151. };
  152.  
  153. struct chunkheader {
  154.   ULONG size;
  155.   UWORD type;
  156. };
  157.  
  158. struct options {
  159.   BOOL ram;
  160.   enum mode_type mode;
  161.   BOOL once;
  162.   BOOL rom;
  163.   BOOL dbuf;
  164.   BOOL cmp;
  165. };
  166.  
  167. #define BITMAP_DEPTH 8
  168.  
  169. PLANEPTR raster[2] = {NULL, NULL};    /* 8 contiguous bitplanes */
  170. struct BitMap screen_bm[2];    /* The displayed bitmap (may be less planes) */
  171. struct BitMap bitmap_bm[2];    /* The full depth-8 bitmap */
  172. struct RastPort rp[2];
  173. UBYTE *buff0 = NULL;        /* CHIP buffer for chunky2planar */
  174. UBYTE *buff1 = NULL;        /* CHIP buffer for chunky2planar */
  175.  
  176. UWORD __chip emptypointer[] = {
  177.     0x0000, 0x0000,        /* reserved, must be NULL */
  178.     0x0000, 0x0000,     /* 1 row of image data */
  179.     0x0000, 0x0000};    /* reserved, must be NULL */
  180.  
  181. struct NewScreen ns = {
  182.         0,0,0,0,0,
  183.         2,1,
  184.         0 /* HIRES | LACE */,
  185.         CUSTOMSCREEN | CUSTOMBITMAP,
  186.         NULL,
  187.         NULL,
  188.         NULL,
  189.         &screen_bm[0]
  190. };
  191.  
  192. struct NewWindow nw = {
  193.         0,0,            /* Starting corner */
  194.         0,0,            /* Width, height */
  195.         2,1,            /* detail, block pens */
  196.         VANILLAKEY,        /* IDCMP flags */
  197.         ACTIVATE|BORDERLESS,    /* Window flags */
  198.         NULL,            /* Pointer to first gadget */
  199.         NULL,            /* Pointer to checkmark */
  200.         NULL,            /* title */
  201.         NULL,            /* screen pointer */
  202.         NULL,            /* bitmap pointer */
  203.         0,0,0,0,        /* window not sized */
  204.         CUSTOMSCREEN        /* type of screen */
  205.         };
  206.  
  207. struct Screen *s = NULL;
  208. struct Window *w = NULL;
  209. UWORD screen_width;
  210. UWORD screen_depth;
  211.  
  212. struct ScreenBuffer *sb[2] = {NULL, NULL};
  213. struct MsgPort *safeport = NULL;
  214. struct MsgPort *dispport = NULL;
  215. BOOL safe = TRUE;
  216. BOOL disp = TRUE;
  217.  
  218. struct RastPort temprp;        /* for WritePixelArray8() */
  219. struct BitMap tmp_bm;        /* for WritePixelArray8(), Height=1, Depth=8 */
  220. PLANEPTR tmpras = NULL;        /* for WritePixelArray8() */
  221.  
  222. struct header h;
  223.  
  224. struct Library *TimerBase = NULL;
  225. struct timerequest *timerio = NULL;
  226. ULONG timerclosed = TRUE;
  227. struct EClockVal *time0 = NULL;
  228. struct EClockVal *time1 = NULL;
  229. double micros_per_eclock;    /* Length of EClock tick in microseconds */
  230.  
  231. struct Task *thistask = NULL;
  232. BOOL v39 = FALSE;
  233. BOOL m68040 = FALSE;
  234.  
  235. char programname[20];
  236. BPTR olddir = NULL;
  237. struct RDArgs *rdargs = NULL;
  238.  
  239. struct Library *AslBase = NULL;
  240. struct FileRequester *fr = NULL;
  241.  
  242.  
  243. /****************************************************************************/
  244.  
  245. void swapw (UWORD *w)
  246. /* Swap the bytes around in a word which may be on an odd byte-boundary */
  247. {
  248.   UBYTE t;
  249.  
  250.   t = ((UBYTE *)w)[0];
  251.   ((UBYTE *)w)[0] = ((UBYTE *)w)[1];
  252.   ((UBYTE *)w)[1] = t;
  253. }
  254.  
  255. void swapl (ULONG *l)
  256. /* Swap the bytes around in a longword which may be on an odd byte-boundary */
  257. {
  258.   UBYTE t;
  259.  
  260.   t = ((UBYTE *)l)[0];
  261.   ((UBYTE *)l)[0] = ((UBYTE *)l)[3];
  262.   ((UBYTE *)l)[3] = t;
  263.   t = ((UBYTE *)l)[1];
  264.   ((UBYTE *)l)[1] = ((UBYTE *)l)[2];
  265.   ((UBYTE *)l)[2] = t;
  266. }
  267.  
  268. UWORD extractw (UWORD *w)
  269. /* Get a word which may be on an odd byte-boundary */
  270. {
  271.   UBYTE t[2];
  272.  
  273.   t[0] = ((UBYTE *)w)[0];
  274.   t[1] = ((UBYTE *)w)[1];
  275.   return *(UWORD *)t;
  276. }
  277.  
  278. ULONG extractl (ULONG *l)
  279. /* Get a longword which may be on an odd byte-boundary */
  280. {
  281.   UBYTE t[4];
  282.  
  283.   t[0] = ((UBYTE *)l)[0];
  284.   t[1] = ((UBYTE *)l)[1];
  285.   t[2] = ((UBYTE *)l)[2];
  286.   t[3] = ((UBYTE *)l)[3];
  287.   return *(ULONG *)t;
  288. }
  289.  
  290. /****************************************************************************/
  291.  
  292. void _STDcleanup (void)
  293. /* This get called automatically by SAS/C 6.3 on any sort of exit condition */
  294. {
  295.   int which;
  296.  
  297.   if (!safe) {
  298.     Wait (1 << safeport->mp_SigBit);
  299.     while (GetMsg (safeport) != NULL) /* clear message queue */
  300.       /* nothing */ ;
  301.     safe = TRUE;
  302.   }
  303.   if (!disp) {
  304.     Wait (1 << dispport->mp_SigBit);
  305.     while (GetMsg (dispport) != NULL) /* clear message queue */
  306.       /* nothing */ ;
  307.     disp = TRUE;
  308.   }
  309.  
  310.   if (w != NULL) {
  311.     CloseWindow (w);
  312.     w = NULL;
  313.   }
  314.   if (sb[1] != NULL) {
  315.     FreeScreenBuffer (s, sb[1]);
  316.     sb[1] = NULL;
  317.   }
  318.   if (sb[0] != NULL) {
  319.     FreeScreenBuffer (s, sb[0]);
  320.     sb[0] = NULL;
  321.   }
  322.   if (s != NULL) {
  323.     CloseScreen (s);
  324.     s = NULL;
  325.   }
  326.   if (tmpras != NULL) {
  327.     FreeRaster (tmpras, screen_width, screen_depth);
  328.     tmpras = NULL;
  329.   }
  330.   if (dispport != NULL) {
  331.     DeletePort (dispport);
  332.     dispport = NULL;
  333.   }
  334.   if (safeport != NULL) {
  335.     DeletePort (safeport);
  336.     safeport = NULL;
  337.   }
  338.   if (buff0 != NULL) {
  339.     FreeMem (buff0, screen_width * (ULONG)h.height);
  340.     buff0 = NULL;
  341.   }
  342.   if (buff1 != NULL) {
  343.     FreeMem (buff1, screen_width * (ULONG)h.height);
  344.     buff1 = NULL;
  345.   }
  346.   for (which = 0; which < 2; which++) {
  347.     if (raster[which] != NULL) {
  348.       FreeRaster (raster[which], screen_width, BITMAP_DEPTH * h.height);
  349.       raster[which] = NULL;
  350.     }
  351.   }
  352.   if (fr != NULL) {
  353.     FreeAslRequest (fr);
  354.     fr = NULL;
  355.   }
  356.   if (AslBase != NULL) {
  357.     CloseLibrary (AslBase);
  358.     AslBase = NULL;
  359.   }
  360.   if (time1 != NULL) {
  361.     FreeMem (time1, sizeof(struct EClockVal));
  362.     time1 = NULL;
  363.   }
  364.   if (time0 != NULL) {
  365.     FreeMem (time0, sizeof(struct EClockVal));
  366.     time0 = NULL;
  367.   }
  368.   if (olddir != NULL) {
  369.     CurrentDir (olddir);
  370.     olddir = NULL;
  371.   }
  372.   if (rdargs != NULL) {
  373.     FreeArgs (rdargs);
  374.     rdargs = NULL;
  375.   }
  376.   if (!timerclosed) {
  377.     CloseDevice ((struct IORequest *)timerio);
  378.     timerclosed = TRUE;
  379.     TimerBase = NULL;
  380.   }
  381.   if (timerio != NULL) {
  382.     FreeMem (timerio, sizeof(struct timerequest));
  383.     timerio = NULL;
  384.   }
  385.   /* standard libraries are auto-closed here by SAS/C */
  386. }
  387.  
  388. /****************************************************************************/
  389.  
  390. void die (char *msg, ...)
  391. /* Exit program with message, return code 10 */
  392. {
  393.   va_list arglist;
  394.  
  395.   WBenchToFront ();
  396.   va_start (arglist, msg);
  397.   vfprintf (stderr, msg, arglist);
  398.   va_end (arglist);
  399.   Delay (50);    /* give the user time to read the message */
  400.   exit (10);
  401.   /* SAS/C executes _STDcleanup() automatically on exit */
  402. }
  403.  
  404. /****************************************************************************/
  405.  
  406. void *malloc_check (size_t size)
  407. {
  408.   void *p;
  409.  
  410.   if ((p = malloc (size)) == NULL)
  411.     die ("%s: Out of memory trying to allocate %ld bytes!\n", programname,
  412.          size);
  413.   return (p);
  414. }
  415.  
  416. /****************************************************************************/
  417.  
  418. void animate_file (char *fname, struct options opt)
  419. {
  420.   FILE *f;
  421.   ULONG size, y, class, totalframes, restartpos, l;
  422.   UWORD i, frame, chunk, code;
  423.   UWORD packets, n, m, c, lines, bsize, depth, which;
  424.   UWORD *viewcolourtable;
  425.   struct IntuiMessage *msg;
  426.   UBYTE *filebuf, *buf, *framebuf, *chunkbuf, *p, *p2, *p3;
  427.   UBYTE *chunky, *compare_chunky[2], *copy_of_chunky;
  428.   UBYTE *restartptr, *xlate;
  429.   UBYTE (*colourtable)[256][3], pattern[2];
  430.   BOOL going, firstloop;
  431.   struct frameheader *fh;
  432.   struct chunkheader *ch;
  433.   ULONG fh_size;
  434.   UWORD fh_magic, fh_chunks, ch_type;
  435.   BOOL palette_changed;
  436.   int oldpri;
  437.  
  438.   /* initialise resources */
  439.   f = NULL;
  440.   viewcolourtable = NULL;
  441.   filebuf = NULL;
  442.   framebuf = NULL;
  443.   chunky = NULL;
  444.   compare_chunky[0] = NULL;
  445.   compare_chunky[1] = NULL;
  446.   copy_of_chunky = NULL;
  447.   xlate = NULL;
  448.   colourtable = NULL;
  449.   fh = NULL;
  450.  
  451.   /* open file and read header struct */
  452.   if ((f = fopen (fname, "rb")) == NULL)
  453.     die ("%s: Can't open %s\n", programname, fname);
  454.   if ((fread (&h, sizeof(struct header), 1, f)) != 1)
  455.     die ("%s: Error reading file\n", programname);
  456.   swapl (&h.size);
  457.   swapw (&h.magic);
  458.   swapw (&h.frames);
  459.   swapw (&h.width);
  460.   swapw (&h.height);
  461.   swapw (&h.depth);
  462.   swapw (&h.flags);
  463.   swapl (&h.speed);
  464.   swapl (&h.creator);
  465.   swapl (&h.updater);
  466.   swapw (&h.aspectx);
  467.   swapw (&h.aspecty);
  468.   swapl (&h.oframe1);
  469.   swapl (&h.oframe2);
  470.  
  471.   printf ("File = %s\n", fname);
  472.   printf ("%lu bytes, %u frames, %ux%ux%u, speed = %u\n", h.size, h.frames,
  473.           h.width, h.height, h.depth, h.speed);
  474.   if (h.magic != 0xaf11 && h.magic != 0xaf12)
  475.     die ("%s: Unrecognised magic number %04x\n", programname, h.magic);
  476.  
  477.   /* allow for AGA modes */
  478.   screen_width = (h.width + 63) & ~63;
  479.  
  480.   /* allocate chunky pixels */
  481.   chunky = malloc_check (screen_width * (ULONG)h.height);
  482.   memset (chunky, 0, screen_width * (ULONG)h.height);
  483.  
  484.   if (opt.rom)
  485.     copy_of_chunky = malloc_check (screen_width * (ULONG)h.height);
  486.  
  487.   /* allocate 2 rasters (for double-buffering) */
  488.   screen_depth = 8;
  489.   for (which = 0; which < (opt.dbuf ? 2 : 1); which++) {
  490.     InitBitMap (&screen_bm[which], screen_depth, screen_width, h.height); /* Displayed bm */
  491.     InitBitMap (&bitmap_bm[which], BITMAP_DEPTH, screen_width, h.height); /* Full depth-8 bm */
  492.     /* Allocate 1 contiguous raster for all 8 planes */
  493.     if ((raster[which] = (PLANEPTR)AllocRaster (screen_width,
  494.                                             BITMAP_DEPTH * h.height)) == NULL)
  495.       die ("%s: Out of CHIP memory!\n", programname);
  496.     for (depth = 0; depth < screen_depth; depth++)
  497.       screen_bm[which].Planes[depth] = raster[which] +
  498.                                        depth * RASSIZE (screen_width, h.height);
  499.     for (depth = 0; depth < BITMAP_DEPTH; depth++)
  500.       bitmap_bm[which].Planes[depth] = raster[which] +
  501.                                        depth * RASSIZE (screen_width, h.height);
  502.     InitRastPort (&rp[which]);
  503.     rp[which].BitMap = &screen_bm[which];
  504.     SetRast (&rp[which], 0);
  505.     /* allocate compare_chunky pixels */
  506.     if (opt.cmp) {
  507.       compare_chunky[which] = malloc_check (screen_width * (ULONG)h.height);
  508.       memset (compare_chunky[which], 0, screen_width * (ULONG)h.height);
  509.     }
  510.   }
  511.  
  512.   /* if using ram then read in the entire file else allocate header buffers */
  513.   if (opt.ram)
  514.     if ((filebuf = malloc (h.size - sizeof(struct header))) == NULL) {
  515.       printf ("%s: Not enough free contiguous memory to load into RAM\n", programname);
  516.       printf ("       Playing from disk instead\n");
  517.       opt.ram = FALSE;
  518.     } else {
  519.       if ((fread (filebuf, h.size - sizeof(struct header), 1, f)) != 1)
  520.         die ("%s: Error reading file\n", programname);
  521.       buf = filebuf;
  522.     }
  523.   if (!opt.ram) {
  524.     fh = malloc_check (sizeof(struct frameheader));
  525.   }
  526.  
  527.   /* open screen with custom bitmap */
  528.   ns.Width = screen_width;
  529.   ns.Height = h.height;
  530.   ns.Depth = screen_depth;
  531.   if (screen_width > 384)
  532.     ns.ViewModes |= HIRES;
  533.   else
  534.     ns.ViewModes &= ~HIRES;
  535.   if (h.height > 283)
  536.     ns.ViewModes |= LACE;
  537.   else
  538.     ns.ViewModes &= ~LACE;
  539.   if (opt.mode == MODE_COLOUR)
  540.     if ((!v39) || (s = OpenScreen(&ns)) == NULL) {
  541.       printf ("%s: Can't open 8 bitplane COLOUR screen\n", programname);
  542.       if (ns.ViewModes & HIRES) {
  543.         printf ("       Using 4 bitplane COLOUR4 instead\n");
  544.         opt.mode = MODE_COLOUR4;
  545.       } else {
  546.         printf ("       Using 6 bitplane EHB instead\n");
  547.         opt.mode = MODE_EHB;
  548.       }
  549.       Delay (100);
  550.     }
  551.   if (opt.mode != MODE_COLOUR) {
  552.     if (opt.mode == MODE_EHB) {
  553.       ns.ViewModes |= EXTRA_HALFBRITE;
  554.       screen_depth = 6;
  555.     } else
  556.       screen_depth = 4;
  557.     ns.Depth = screen_depth;
  558.     for (which = 0; which < (opt.dbuf ? 2 : 1); which++)
  559.       screen_bm[which].Depth = screen_depth;
  560.     if ((s = OpenScreen(&ns)) == NULL)
  561.       die ("%s: Can't open screen!\n", programname);
  562.   }
  563.  
  564.   /* initialise tmp stuff for WritePixelArray8() */
  565.   if (opt.rom) {
  566.     if ((tmpras = (PLANEPTR)AllocRaster (screen_width, screen_depth)) == NULL)
  567.       die ("%s: Out of memory\n", programname);
  568.     InitBitMap (&tmp_bm, screen_depth, screen_width, 1);
  569.     for (depth = 0; depth < screen_depth; depth++)
  570.       tmp_bm.Planes[depth] = tmpras + depth * RASSIZE (screen_width, 1);
  571.     temprp = rp[0];
  572.     temprp.Layer = NULL;
  573.     temprp.BitMap = &tmp_bm;
  574.   } else if ((!opt.cmp) && !m68040) {
  575.     /* allocate scratch buffers in chip ram for blitter in chunky2planar */
  576.     if ((buff0 = AllocMem (screen_width * (ULONG)h.height, MEMF_CHIP)) == NULL)
  577.       die ("%s: Out of CHIP memory trying to allocate %ld bytes!\n",
  578.            programname, screen_width * (ULONG)h.height);
  579.     if ((buff1 = AllocMem (screen_width * (ULONG)h.height, MEMF_CHIP)) == NULL)
  580.       die ("%s: Out of CHIP memory trying to allocate %ld bytes!\n",
  581.            programname, screen_width * (ULONG)h.height);
  582.   }
  583.  
  584.   /* allocate structures for double-buffering (if v39) */
  585.   if (v39 && opt.dbuf) {
  586.     if ((safeport = CreatePort (NULL, 0)) == NULL ||
  587.         (dispport = CreatePort (NULL, 0)) == NULL)
  588.       die ("%s: Can't create port!\n", programname);
  589.     for (which = 0; which < 2; which++) {
  590.       if ((sb[which] = AllocScreenBuffer (s, &screen_bm[which], 0)) == NULL)
  591.         die ("%s: Can't allocate ScreenBuffer!\n", programname);
  592.       sb[which]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = safeport;
  593.       sb[which]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = dispport;
  594.     }
  595.   }
  596.  
  597.   /* open a backdrop window (for intuition events) */
  598.   nw.Width = screen_width;
  599.   nw.Height = h.height;
  600.   nw.Screen = s;
  601.   nw.MinWidth = screen_width;
  602.   nw.MinHeight = h.height;
  603.   nw.MaxWidth = screen_width;
  604.   nw.MaxHeight = h.height;
  605.   if ((w = OpenWindow(&nw)) == NULL)
  606.     die ("%s: Can't open window!\n", programname);
  607.  
  608.   /* turn the mouse pointer off for this window */
  609.   SetPointer (w, emptypointer, 1, 16, 0, 0);
  610.  
  611.   /* allocate and initialise colour tables and pixel xlate table */
  612.   colourtable = (UBYTE (*)[256][3])malloc_check (sizeof(*colourtable));
  613.   memset (colourtable, 0, sizeof(*colourtable));
  614.   xlate = malloc_check (256);
  615.  
  616.   switch (opt.mode) {
  617.     case MODE_COLOUR4:
  618.     case MODE_EHB:
  619.       viewcolourtable = (UWORD *)malloc_check ((1 << screen_depth) * sizeof(UWORD));
  620.       memset (viewcolourtable, 0, (1 << screen_depth) * sizeof(UWORD));
  621.       break;
  622.     case MODE_GREY:
  623.       viewcolourtable = (UWORD *)malloc_check ((1 << screen_depth) * sizeof(UWORD));
  624.       memset (viewcolourtable, 0, (1 << screen_depth) * sizeof(UWORD));
  625.       for (c = 0; c < 16; c++)
  626.         viewcolourtable[c] = c * 0x0111;
  627.       LoadRGB4 (&s->ViewPort, viewcolourtable, 1 << screen_depth);
  628.       break;
  629.     case MODE_COLOUR:
  630.       viewcolourtable = (UWORD *)malloc_check (2 * sizeof(UWORD) +
  631.                        (1 << screen_depth) * 3 * sizeof(ULONG) + sizeof(UWORD));
  632.       memset (viewcolourtable, 0, 2 * sizeof(UWORD) +
  633.                        (1 << screen_depth) * 3 * sizeof(ULONG) + sizeof(UWORD));
  634.       viewcolourtable[0] = 1 << screen_depth;
  635.       for (i = 0; i < 256; i++)
  636.         xlate[i] = i;
  637.       break;
  638.   }
  639.  
  640.   /* initialise loop variables */
  641.   which = 0;    /* bitmap index --- flips between 0 and 1 with each frame */
  642.   palette_changed = FALSE;
  643.   frame = 0;
  644.   totalframes = 0;
  645.   firstloop = TRUE;
  646.   going = TRUE;
  647.  
  648.   /* read the start time */
  649.   ReadEClock (time0);
  650.  
  651.   /* loop for each frame */
  652.   while (going) {
  653.  
  654.     /* if this is the 2nd frame, save the current file-position for loop */
  655.     if (totalframes == 1)
  656.       if (opt.ram)
  657.         restartptr = buf;
  658.       else
  659.         if ((restartpos = ftell (f)) == -1)
  660.           die ("%s: Error ftelling file\n", programname);
  661.  
  662.     /* read the frame header */
  663.     if (opt.ram) {
  664.       fh = (struct frameheader *)buf;
  665.       buf += sizeof(struct frameheader);
  666.     } else
  667.       if ((fread (fh, sizeof(struct frameheader), 1, f)) != 1)
  668.         die ("%s: Error reading file\n", programname);
  669.     if (firstloop || !opt.ram) {
  670.       swapl (&fh->size);
  671.       swapw (&fh->magic);
  672.       swapw (&fh->chunks);
  673.     }
  674.     fh_size = extractl (&fh->size);
  675.     fh_magic = extractw (&fh->magic);
  676.     fh_chunks = extractw (&fh->chunks);
  677.  
  678.     /* allocate memory for and read the rest of the frame */
  679.     if (opt.ram) {
  680.       framebuf = buf;
  681.     } else {
  682.       size = fh_size - sizeof(struct frameheader);
  683.       if (size == 0)
  684.         framebuf = NULL;
  685.       else {
  686.         framebuf = malloc_check (size);
  687.         if ((fread (framebuf, size, 1, f)) != 1)
  688.           die ("%s: Error reading file\n", programname);
  689.         buf = framebuf;
  690.       }
  691.     }
  692.  
  693.     /* check for and ignore 0xf100 frames */
  694.     if (fh_magic == 0xf100) {
  695.  
  696.       totalframes--;    /* don't count this frame */
  697.       frame--;
  698.  
  699.     } else {
  700.  
  701.       /* consistency check */
  702.       if (fh_magic != 0xf1fa)
  703.         die ("%s: Unrecognised magic number in frame %04x %lu\n",
  704.                  programname, fh_magic, fh_size);
  705.  
  706.       /* loop for each chunk */
  707.       for (chunk = 0; chunk < fh_chunks; chunk++) {
  708.  
  709.         /* examine the chunk header */
  710.         ch = (struct chunkheader *)buf;
  711.         if (firstloop || !opt.ram) {
  712.           swapl (&ch->size);
  713.           swapw (&ch->type);
  714.         }
  715.         chunkbuf = buf + sizeof(struct chunkheader);
  716.         buf += (extractl (&ch->size) + 1) & ~1;
  717.         ch_type = extractw (&ch->type);
  718.  
  719.         /* uncompress chunk into chunky pixels */
  720.         switch (ch_type) {
  721.  
  722.           case FLI_SS2:
  723.             p = chunkbuf;
  724.             p2 = chunky;
  725.             lines = *p++;
  726.             lines |= (*p++ << 8);
  727.             for ( ; lines > 0; lines--) {
  728.               do {
  729.                 packets = *p++;
  730.                 packets |= (*p++ << 8);
  731.                 if (packets > 32767)
  732.                   if (packets > 49151)
  733.                     p2 += (65536 - packets) * (ULONG)screen_width;
  734.                   else
  735.                     *(p2 + screen_width - 1) = (packets & 0xff);
  736.               } while (packets >= 32768);
  737.               p3 = p2;
  738.               for ( ; packets > 0; packets--) {
  739.                 p3 += *p++;
  740.                 bsize = *p++;
  741.                 if (bsize > 127) {
  742.                   bsize = 256 - bsize;
  743.                   if (opt.mode == MODE_COLOUR) {
  744. /*
  745.                     repmem (p3, p, 2, bsize);
  746.                     p3 += (bsize << 1);
  747. */
  748.                     for (i = bsize; i > 0; i--) {
  749.                       *p3++ = *p;
  750.                       *p3++ = *(p + 1);
  751.                     }
  752.                     p += 2;
  753.                   } else {
  754.                     pattern[1] = xlate[*p++];
  755.                     pattern[0] = xlate[*p++];
  756. /*
  757.                     repmem (p3, pattern, 2, bsize);
  758.                     p3 += (bsize << 1);
  759. */
  760.                     for (i = bsize; i > 0; i--) {
  761.                       *p3++ = pattern[1];
  762.                       *p3++ = pattern[0];
  763.                     }
  764.                   }
  765.                 } else {
  766.                   bsize <<= 1;
  767.                   if (opt.mode == MODE_COLOUR) {
  768.                     memcpy (p3, p, bsize);
  769. /*
  770.                     CopyMem (p, p3, bsize);
  771. */
  772.                     p += bsize;
  773.                     p3 += bsize;
  774.                   } else
  775.                     for (i = bsize; i > 0; i--)
  776.                       *p3++ = xlate[*p++];
  777.                 }
  778.               }
  779.               p2 += screen_width;
  780.             }
  781.             break;
  782.  
  783.           case FLI_256_COLOR:
  784.           case FLI_COLOR:
  785.             p = chunkbuf;
  786.             packets = *p++;
  787.             packets |= (*p++ << 8);
  788.             c = 0;
  789.             for ( ; packets > 0; packets--) {
  790.               c += *p++;
  791.               n = *p++;
  792.               if (n == 0)
  793.                 n = 256;
  794.               for (m = 0; m < n; m++) {
  795.                 if (ch_type == FLI_256_COLOR) {
  796.                   (*colourtable)[c][0] = *p++;        /* R */
  797.                   (*colourtable)[c][1] = *p++;        /* G */
  798.                   (*colourtable)[c][2] = *p++;        /* B */
  799.                 } else {
  800.                   (*colourtable)[c][0] = *p++ << 2;    /* R */
  801.                   (*colourtable)[c][1] = *p++ << 2;    /* G */
  802.                   (*colourtable)[c][2] = *p++ << 2;    /* B */
  803.                 }
  804.                 c++;
  805.               }
  806.             }
  807.             switch (opt.mode) {
  808.               case MODE_COLOUR4:
  809.               case MODE_EHB:
  810.                 median_cut (*colourtable, viewcolourtable, xlate, opt.mode);
  811.                 break;
  812.               case MODE_GREY:
  813.                 for (c = 0; c < 256; c++)
  814.                   xlate[c] = ((((UWORD)(*colourtable)[c][0]) +
  815.                                ((UWORD)(*colourtable)[c][1]) +
  816.                                ((UWORD)(*colourtable)[c][2])) / 3) >> 4;
  817.                 break;
  818.               case MODE_COLOUR:
  819.                 break;
  820.             }
  821.             palette_changed = TRUE;
  822.             break;            
  823.  
  824.           case FLI_LC:
  825.             p = chunkbuf;
  826.             y = *p++;
  827.             y |= (*p++ << 8);
  828.             p2 = &chunky[y * screen_width];
  829.             lines = *p++;
  830.             lines |= (*p++ << 8);
  831.             for ( ; lines > 0; lines--) {
  832.               p3 = p2;
  833.               for (packets = *p++; packets > 0; packets--) {
  834.                 p3 += *p++;
  835.                 bsize = *p++;
  836.                 if (bsize > 127) {
  837.                   bsize = 256 - bsize;
  838.                   memset (p3, xlate[*p++], bsize);
  839.                   p3 += bsize;
  840.                 } else {
  841.                   if (opt.mode == MODE_COLOUR) {
  842.                     memcpy (p3, p, bsize);
  843. /*
  844.                     CopyMem (p, p3, bsize);
  845. */
  846.                     p += bsize;
  847.                     p3 += bsize;
  848.                   } else
  849.                     for (i = bsize; i > 0; i--)
  850.                       *p3++ = xlate[*p++];
  851.                 }
  852.               }
  853.               p2 += screen_width;
  854.             }
  855.             break;
  856.  
  857.           case FLI_BLACK:
  858.             memset (chunky, xlate[0], screen_width * (ULONG)h.height);
  859.             break;
  860.  
  861.           case FLI_BRUN:
  862.             p = chunkbuf;
  863.             p2 = chunky;
  864.             for (lines = h.height; lines > 0; lines--) {
  865.               p3 = p2 + h.width;
  866.               p++;    /* skip packet count */
  867.               while (p2 < p3) {
  868.                 bsize = *p++;
  869.                 if (bsize <= 127) {
  870.                   memset (p2, xlate[*p++], bsize);
  871.                   p2 += bsize;
  872.                 } else {
  873.                   bsize = 256 - bsize;
  874.                   if (opt.mode == MODE_COLOUR) {
  875.                     memcpy (p2, p, bsize);
  876. /*
  877.                     CopyMem (p, p2, bsize);
  878. */
  879.                     p += bsize;
  880.                     p2 += bsize;
  881.                   } else
  882.                     for (i = bsize; i > 0; i--)
  883.                       *p2++ = xlate[*p++];
  884.                 }
  885.               }
  886.               p2 += (screen_width - h.width);
  887.             }
  888.             break;
  889.  
  890.           case FLI_COPY:
  891.             if (opt.mode == MODE_COLOUR)
  892.               if (h.width == screen_width) {
  893. /*
  894.                 memcpy (chunky, chunkbuf, h.width * (ULONG)h.height);
  895. */
  896.                 CopyMemQuick (chunkbuf, chunky, screen_width * (ULONG)h.height);
  897.               } else {
  898.                 p = chunkbuf;
  899.                 p2 = chunky;
  900.                 for (lines = h.height; lines > 0; lines--) {
  901.                   CopyMemQuick (p, p2, h.width);
  902.                   p += h.width;
  903.                   p2 += screen_width;
  904.                 }
  905.               }
  906.             else {
  907.               if (h.width == screen_width) {
  908.                 p2 = chunky;
  909.                 for (l = h.width * (ULONG)h.height; l > 0; l--)
  910.                   *p2++ = xlate[*p++];
  911.               } else {
  912.                 p = chunkbuf;
  913.                 p2 = chunky;
  914.                 for (lines = h.height; lines > 0; lines--) {
  915.                   for (i = h.width; i > 0; i--)
  916.                     *p2++ = xlate[*p++];
  917.                   p2 += (screen_width - h.width);
  918.                 }
  919.               }
  920.             }
  921.             break;
  922.  
  923.           case FLI_PSTAMP:
  924.             break;
  925.  
  926.           default:
  927.             die ("%s: Unrecognised chunk type %04x\n", programname, ch_type);
  928.             break;
  929.         } /* end of switch for each chunk type */
  930.  
  931.       } /* end of loop for each chunk within frame */
  932.  
  933.       /* update amiga's colourtable if palette has changed in this frame */
  934.       if (palette_changed) {
  935.         switch (opt.mode) {
  936.           case MODE_COLOUR4:
  937.             LoadRGB4 (&s->ViewPort, viewcolourtable, 16);
  938.             break;
  939.           case MODE_EHB:
  940.             LoadRGB4 (&s->ViewPort, viewcolourtable, 32);
  941.             break;
  942.           case MODE_GREY:
  943.             break;
  944.           case MODE_COLOUR:
  945.             for (c = 0; c < (1 << screen_depth); c++) {
  946.               ((ULONG *)viewcolourtable)[3*c+1] = (*colourtable)[c][0] << 24;
  947.               ((ULONG *)viewcolourtable)[3*c+2] = (*colourtable)[c][1] << 24;
  948.               ((ULONG *)viewcolourtable)[3*c+3] = (*colourtable)[c][2] << 24;
  949.             }
  950.             LoadRGB32 (&s->ViewPort, (ULONG *)viewcolourtable);
  951.             break;
  952.         }
  953.         palette_changed = FALSE;
  954.       }
  955.  
  956.       /* Wait until it is safe to modify bitmap without flicker (if v39) */
  957.       if (v39 && opt.dbuf) {
  958.         if (!safe) {
  959.           Wait (1 << safeport->mp_SigBit);
  960.           while (GetMsg (safeport) != NULL) /* clear message queue */
  961.             /* nothing */ ;
  962.           safe = TRUE;
  963.         }
  964.       }
  965.  
  966.       /* render into the non-displayed raster (if double-buffering) */
  967.       if (opt.dbuf)
  968.         which = 1 - which;
  969.  
  970.       /* convert from chunky pixels to (hidden) planar raster[which] */
  971.       if (opt.rom) {
  972.         /* WritePixelArray8() destroys original chunky, so make a copy */
  973.         CopyMemQuick (chunky, copy_of_chunky, screen_width * (ULONG)h.height);
  974.         WritePixelArray8 (&rp[which], 0, 0, screen_width-1, h.height-1,
  975.                           copy_of_chunky, &temprp);
  976.       } else if (opt.cmp) {
  977.         switch (screen_depth) {
  978.           case 4:
  979.             c2p_4_cmp (chunky, raster[which], compare_chunky[which],
  980.                        (screen_width * (ULONG)h.height) >> 3);
  981.             break;
  982.           case 6:
  983.             if (screen_width == 320 && h.height == 200)
  984.               c2p320x200x6_cmp (chunky, raster[which], compare_chunky[which]);
  985.             else
  986.               c2p_6_cmp (chunky, raster[which], compare_chunky[which],
  987.                          (screen_width * (ULONG)h.height) >> 3);
  988.             break;
  989.           case 8:
  990.             if (screen_width == 320 && h.height == 200)
  991.               c2p320x200x8_cmp (chunky, raster[which], compare_chunky[which]);
  992.             else
  993.               c2p_8_cmp (chunky, raster[which], compare_chunky[which],
  994.                          (screen_width * (ULONG)h.height) >> 3);
  995.             break;
  996.           default:
  997.             die ("%s: Unsupported resolution\n", programname);
  998.             break;
  999.         }
  1000.       } else if (m68040) {
  1001.         switch (screen_depth) {
  1002.           case 4:
  1003.             c2p_4_040 (chunky, raster[which],
  1004.                        (screen_width * (ULONG)h.height) >> 3);
  1005.             break;
  1006.           case 6:
  1007.             if (screen_width == 320 && h.height == 200)
  1008.               c2p320x200x6_040 (chunky, raster[which]);
  1009.             else
  1010.               c2p_6_040 (chunky, raster[which],
  1011.                          (screen_width * (ULONG)h.height) >> 3);
  1012.             break;
  1013.           case 8:
  1014.             if (screen_width == 320 && h.height == 200)
  1015.               c2p320x200x8_040 (chunky, raster[which]);
  1016.             else
  1017.               c2p_8_040 (chunky, raster[which],
  1018.                          (screen_width * (ULONG)h.height) >> 3);
  1019.             break;
  1020.           default:
  1021.             die ("%s: Unsupported resolution\n", programname);
  1022.             break;
  1023.         }
  1024.       } else {
  1025.         switch (screen_depth) {
  1026.           case 4:
  1027.             c2p_4 (chunky, raster[which], buff0, buff1,
  1028.                    TimerBase, GfxBase, UtilityBase,
  1029.                    (screen_width * (ULONG)h.height) >> 3);
  1030.             break;
  1031.           case 6:
  1032.             if (screen_width == 320 && h.height == 200)
  1033.               c2p320x200x6 (chunky, raster[which], buff0, buff1,
  1034.                             TimerBase, GfxBase, UtilityBase);
  1035.             else
  1036.               c2p_6 (chunky, raster[which], buff0, buff1,
  1037.                      TimerBase, GfxBase, UtilityBase,
  1038.                      (screen_width * (ULONG)h.height) >> 3);
  1039.             break;
  1040.           case 8:
  1041.             if (screen_width == 320 && h.height == 200)
  1042.               c2p320x200x8 (chunky, raster[which], buff0, buff1,
  1043.                             TimerBase, GfxBase, UtilityBase);
  1044.             else
  1045.               c2p_8 (chunky, raster[which], buff0, buff1,
  1046.                      TimerBase, GfxBase, UtilityBase,
  1047.                      (screen_width * (ULONG)h.height) >> 3);
  1048.             break;
  1049.           default:
  1050.             die ("%s: Unsupported resolution\n", programname);
  1051.             break;
  1052.         }
  1053.       }
  1054.  
  1055.       /* make the new raster visible (if double-buffering) */
  1056.       if (opt.dbuf) {
  1057.         if (v39) {
  1058.           oldpri = SetTaskPri (thistask, 20); /* don't flicker when mouse moves */
  1059.           /* Wait until it is safe to swap bitmaps without flicker */
  1060.           if (!disp) {
  1061.             Wait (1 << dispport->mp_SigBit);
  1062.             while (GetMsg (dispport) != NULL) /* clear message queue */
  1063.               /* nothing */ ;
  1064.             disp = TRUE;
  1065.           }
  1066.           if (ChangeScreenBuffer (s, sb[which])) {
  1067.             disp = FALSE;
  1068.             safe = FALSE;
  1069.           }
  1070.           SetTaskPri (thistask, oldpri); /* restore task priority */
  1071.         } else {
  1072.           s->ViewPort.RasInfo->BitMap = &screen_bm[which];
  1073.           MakeScreen (s);
  1074.           RethinkDisplay ();
  1075.         }
  1076.       }
  1077.  
  1078.       /* check for CTRL/C or BREAK */
  1079.       if (SetSignal (0, 0) & SIGBREAKF_CTRL_C) {
  1080.         SetSignal (0, SIGBREAKF_CTRL_C);
  1081.         printf ("***Break\n");
  1082.         exit (0);
  1083.       }
  1084.  
  1085.       /* check for intuition messages */
  1086.       while ((msg = (struct IntuiMessage *)GetMsg (w->UserPort)) != NULL) {
  1087.         class = msg->Class;
  1088.         code = msg->Code;
  1089.         ReplyMsg ((struct Message *)msg);
  1090.         if (class == IDCMP_VANILLAKEY)
  1091.           switch (code) {
  1092.             case 0x03: /* CTRL/C */
  1093.               printf ("***Break\n");
  1094.               exit (0);
  1095.             case 0x1b: /* ESC */
  1096.             case 0x51: /* q */
  1097.             case 0x71: /* Q */
  1098.               going = FALSE;
  1099.               break;
  1100.             default:
  1101.               break;
  1102.           }
  1103.       }
  1104.  
  1105.     } /* end of if frame magic != 0xf100 */
  1106.  
  1107.     /* seek to the beginning of the next frame or deallocate frame ram */
  1108.     if (opt.ram)
  1109.       buf = framebuf + fh_size - sizeof(struct frameheader);
  1110.     else
  1111.       if (framebuf != NULL)
  1112.         free (framebuf);
  1113.     framebuf = NULL;
  1114.  
  1115.     /* seek back to frame 1 (the 2nd frame) when we get to the last frame */
  1116.     if (frame++ == h.frames)
  1117.       if (opt.once)
  1118.         going = FALSE;
  1119.       else {
  1120.         firstloop = FALSE;
  1121.         frame = 1;
  1122.         if (opt.ram)
  1123.           buf = restartptr;
  1124.         else
  1125.           if (fseek (f, restartpos, SEEK_SET) == -1)
  1126.             die ("%s: Error seeking file\n", programname);
  1127.       }
  1128.  
  1129.     totalframes++;
  1130.  
  1131.   } /* end of loop for each frame */
  1132.  
  1133.   /* cleanup pending messages */
  1134.   if (!safe) {
  1135.     Wait (1 << safeport->mp_SigBit);
  1136.     while (GetMsg (safeport) != NULL) /* clear message queue */
  1137.       /* nothing */ ;
  1138.     safe = TRUE;
  1139.   }
  1140.   if (!disp) {
  1141.     Wait (1 << dispport->mp_SigBit);
  1142.     while (GetMsg (dispport) != NULL) /* clear message queue */
  1143.       /* nothing */ ;
  1144.     disp = TRUE;
  1145.   }
  1146.  
  1147.   /* find out and display how long it took */
  1148.   ReadEClock (time1);
  1149.   printf ("%s: Frames per second = %5.2lf\n", programname,
  1150.           1000000.0 * totalframes /
  1151.           (((time1->ev_hi - time0->ev_hi) * 4294967296.0
  1152.           + (time1->ev_lo - time0->ev_lo)) * micros_per_eclock));
  1153.  
  1154.   /* close files and free memory */
  1155.   if (f != NULL) {
  1156.     fclose (f);
  1157.     f = NULL;
  1158.   }
  1159.   if (colourtable != NULL) {
  1160.     free (colourtable);
  1161.     colourtable = NULL;
  1162.   }
  1163.   if (viewcolourtable != NULL) {
  1164.     free (viewcolourtable);
  1165.     viewcolourtable = NULL;
  1166.   }
  1167.   if (xlate != NULL) {
  1168.     free (xlate);
  1169.     xlate = NULL;
  1170.   }
  1171.   if (filebuf != NULL) {
  1172.     free (filebuf);
  1173.     filebuf = NULL;
  1174.   }
  1175.   if (!opt.ram) {
  1176.     if (fh != NULL) {
  1177.       free (fh);
  1178.       fh = NULL;
  1179.     }
  1180.   }
  1181.   if (compare_chunky[1] != NULL) {
  1182.     free (compare_chunky[1]);
  1183.     compare_chunky[1] = NULL;
  1184.   }
  1185.   if (compare_chunky[0] != NULL) {
  1186.     free (compare_chunky[0]);
  1187.     compare_chunky[0] = NULL;
  1188.   }
  1189.   if (chunky != NULL) {
  1190.     free (chunky);
  1191.     chunky = NULL;
  1192.   };
  1193.   if (copy_of_chunky != NULL) {
  1194.     free (copy_of_chunky);
  1195.     copy_of_chunky = NULL;
  1196.   }
  1197.   if (w != NULL) {
  1198.     CloseWindow (w);
  1199.     w = NULL;
  1200.   }
  1201.   if (sb[1] != NULL) {
  1202.     FreeScreenBuffer (s, sb[1]);
  1203.     sb[1] = NULL;
  1204.   }
  1205.   if (sb[0] != NULL) {
  1206.     FreeScreenBuffer (s, sb[0]);
  1207.     sb[0] = NULL;
  1208.   }
  1209.   if (dispport != NULL) {
  1210.     DeletePort (dispport);
  1211.     dispport = NULL;
  1212.   }
  1213.   if (safeport != NULL) {
  1214.     DeletePort (safeport);
  1215.     safeport = NULL;
  1216.   }
  1217.   if (s != NULL) {
  1218.     CloseScreen (s);
  1219.     s = NULL;
  1220.   }
  1221.   if (tmpras != NULL) {
  1222.     FreeRaster (tmpras, screen_width, screen_depth);
  1223.     tmpras = NULL;
  1224.   }
  1225.   if (buff1 != NULL) {
  1226.     FreeMem (buff1, screen_width * (ULONG)h.height);
  1227.     buff1 = NULL;
  1228.   }
  1229.   if (buff0 != NULL) {
  1230.     FreeMem (buff0, screen_width * (ULONG)h.height);
  1231.     buff0 = NULL;
  1232.   }
  1233.   if (raster[1] != NULL) {
  1234.     FreeRaster (raster[1], screen_width, BITMAP_DEPTH * h.height);
  1235.     raster[1] = NULL;
  1236.   }
  1237.   if (raster[0] != NULL) {
  1238.     FreeRaster (raster[0], screen_width, BITMAP_DEPTH * h.height);
  1239.     raster[0] = NULL;
  1240.   }
  1241. }
  1242.  
  1243. /****************************************************************************/
  1244.  
  1245. struct TagItem frtags[] = {
  1246.   {ASL_Hail,        0},
  1247.   {ASL_Pattern,        (ULONG)"#?.fl[ic]"},
  1248.   {ASL_OKText,        (ULONG)"Play"},
  1249.   {ASL_CancelText,    (ULONG)"Cancel"},
  1250.   {ASL_FuncFlags,    FILF_PATGAD},
  1251.   {TAG_DONE,        0}
  1252. };
  1253.  
  1254. char resultstring[128];
  1255.  
  1256. void filerequestloop (struct options *opt)
  1257. {
  1258.   if ((AslBase = OpenLibrary ("asl.library", 37L)) != NULL) {
  1259.     frtags[0].ti_Data = (ULONG)programname;
  1260.     if (AslBase->lib_Version < 39)
  1261.       frtags[1].ti_Data = (ULONG)"#?.fl?";
  1262.     if ((fr = (struct FileRequester *)AllocAslRequest
  1263.                                           (ASL_FileRequest, frtags)) != NULL) {
  1264.       while (AslRequest (fr, NULL)) {
  1265.         strcpy (resultstring, fr->rf_Dir);
  1266.         AddPart (resultstring, fr->rf_File, 128);
  1267.         animate_file (resultstring, *opt);
  1268.       }
  1269.       FreeAslRequest (fr);
  1270.       fr = NULL;
  1271.     }
  1272.     CloseLibrary (AslBase);
  1273.     AslBase = NULL;
  1274.   }
  1275. }
  1276.  
  1277. /****************************************************************************/
  1278.  
  1279. LONG argarray[14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  1280.  
  1281. int main (int argc, char *argv[])
  1282. {
  1283.   struct WBStartup *argmsg;
  1284.   struct WBArg *wb_arg;
  1285.   char **fnames;
  1286.   UWORD ktr;
  1287.   struct options opt;
  1288.  
  1289.  
  1290.   /* standard libraries are auto-opened here by SAS/C */
  1291.  
  1292.   /* find out about ourself */
  1293.   thistask = FindTask (NULL);
  1294.   GetProgramName (programname, 19);
  1295.   v39 = (GfxBase->LibNode.lib_Version >= 39);
  1296.   m68040 = (SysBase->AttnFlags & AFF_68040) != 0;
  1297.  
  1298.   /* timer stuff */
  1299.   if ((timerio = (struct timerequest *)AllocMem (sizeof(struct timerequest),
  1300.                                            MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
  1301.     die ("%s: Out of memory\n", programname);
  1302.   if (timerclosed = OpenDevice (TIMERNAME, UNIT_MICROHZ,
  1303.                                 (struct IORequest *)timerio, 0))
  1304.     die ("%s: Can't open timer.device!\n", programname);
  1305.   TimerBase = (struct Library *)timerio->tr_node.io_Device;
  1306.   if ((time0 = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
  1307.                                              MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
  1308.     die ("%s: Out of memory\n", programname);
  1309.   if ((time1 = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
  1310.                                              MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
  1311.     die ("%s: Out of memory\n", programname);
  1312.   micros_per_eclock = 1000000.0 / (double)ReadEClock (time0);
  1313.  
  1314.   /* set default switches */
  1315.   opt.ram = TRUE;
  1316.   opt.mode = MODE_COLOUR;
  1317.   opt.once = FALSE;
  1318.   opt.rom = FALSE;
  1319.   opt.dbuf = TRUE;
  1320.   opt.cmp = TRUE;
  1321.  
  1322.   /* parse workbench message or commandline */
  1323.   if (argc == 0) {
  1324.     argmsg = (struct WBStartup *)argv;
  1325.     wb_arg = argmsg->sm_ArgList;
  1326.     strcpy (programname, wb_arg->wa_Name);
  1327.     if (argmsg->sm_NumArgs <= 1)
  1328.       filerequestloop (&opt);
  1329.     else {
  1330.       wb_arg++;
  1331.       for (ktr = 1; ktr < argmsg->sm_NumArgs; ktr++, wb_arg++)
  1332.         if (wb_arg->wa_Lock != NULL) {
  1333.           olddir = CurrentDir (wb_arg->wa_Lock);
  1334.           animate_file (wb_arg->wa_Name, opt);
  1335.           CurrentDir (olddir);
  1336.           olddir = NULL;
  1337.         } else
  1338.           animate_file (wb_arg->wa_Name, opt);
  1339.       }
  1340.   } else {
  1341.     if ((rdargs = ReadArgs
  1342.         ("FILE/M,DISK/S,RAM/S,ONCE/S,COLOUR/S,COLOR/S,EHB/S,COLOUR4/S,COLOR4/S,GREY/S,GRAY/S,ROM/S,NODBUF/S,NOCOMPARE/S",
  1343.                             argarray, NULL)) != NULL) {
  1344.       if (argarray[1])
  1345.         opt.ram = FALSE;
  1346.       if (argarray[2])
  1347.         opt.ram = TRUE;
  1348.       if (argarray[3])
  1349.         opt.once = TRUE;
  1350.       if (argarray[4] || argarray[5])
  1351.         opt.mode = MODE_COLOUR;
  1352.       if (argarray[6])
  1353.         opt.mode = MODE_EHB;
  1354.       if (argarray[7] || argarray[8])
  1355.         opt.mode = MODE_COLOUR4;
  1356.       if (argarray[9] || argarray[10])
  1357.         opt.mode = MODE_GREY;
  1358.       if (argarray[11])
  1359.         opt.rom = TRUE;
  1360.       if (argarray[12])
  1361.         opt.dbuf = FALSE;
  1362.       if (argarray[13])
  1363.         opt.cmp = FALSE;
  1364.       fnames = (char **)argarray[0];
  1365.       if (fnames == NULL || *fnames == NULL)
  1366.         filerequestloop (&opt);
  1367.       else
  1368.         while (*fnames != NULL)
  1369.           animate_file (*fnames++, opt);
  1370.       FreeArgs (rdargs);
  1371.       rdargs = NULL;
  1372.     }
  1373.   }
  1374.  
  1375.   /* Let the user see how fast it went before the window closes */
  1376.   if (argc == 0)
  1377.     Delay (200);
  1378.  
  1379.   /* exit program with success code */
  1380.   return (0);
  1381.  
  1382.   /* SAS/C executes _STDcleanup() automatically on exit or break */
  1383.  
  1384. }
  1385.  
  1386. /****************************************************************************/
  1387.